package com.pine.web.config;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.pine.common.beans.LogId;
import com.pine.common.systemlog.SysLogVo;
import com.pine.common.systemlog.event.SysLogEventListener;
import com.pine.dao.pineframework.constants.LogTypeEnum;
import com.pine.dao.pineframework.entity.SysDict;
import com.pine.dao.pineframework.entity.SysLog;
import com.pine.manager.core.DesensitizedOnJsonComponent;
import com.pine.manager.core.StringPool;
import com.pine.manager.pineframework.SysDictItemManager;
import com.pine.manager.pineframework.SysDictManager;
import com.pine.manager.pineframework.SysLogManager;
import com.pine.manager.pineframework.bo.SysDictBo;
import com.pine.manager.pineframework.bo.SysDictItemBo;
import com.pine.manager.pineframework.query.SysDictItemQuery;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

/**
 * 日志配置
 *
 * @author pine manage
 * @since 2024-08-14
 */
@Slf4j
@Configuration
public class LogConfiguration {

    @Resource
    private SysLogManager sysLogManager;

    @Resource
    private SysDictManager sysDictManager;

    @Resource
    private SysDictItemManager sysDictItemManager;

    @Bean
    @ConditionalOnProperty(name = {"pine.common.system-log.enable"}, havingValue = "true")
    @Primary
    public SysLogEventListener sysLogEventListener() {
        initDesensitizedFieldConfig();

        List<Consumer<SysLogVo>> consumers = new ArrayList<>();
        consumers.add(vo -> {
            LogId.put(vo.getLogId());
            // 数据脱敏
            String desensitizedRequestParam = DesensitizedOnJsonComponent.desensitized(vo.getRequestParam());
            String desensitizedResponseParam = DesensitizedOnJsonComponent.desensitized(vo.getResponseParam());
            vo.setRequestParam(desensitizedRequestParam);
            vo.setResponseParam(desensitizedResponseParam);
            log.info("sys-log: {}", vo);
        });

        // 记录到数据库
        consumers.add(vo -> {
            LogId.put(vo.getLogId());
            SysLog sysLog = new SysLog();
            sysLog.setLogId(vo.getLogId());
            sysLog.setRequestIp(vo.getRequestIp());
            if (ObjectUtil.isNotEmpty(vo.getLogType())) {
                sysLog.setLogType(LogTypeEnum.of(vo.getLogType().getCode()));
            }
            sysLog.setDescription(vo.getDescription());
            sysLog.setClassPath(vo.getClassPath());
            sysLog.setActionMethod(vo.getActionMethod());
            sysLog.setHttpMethod(vo.getHttpMethod());
            sysLog.setRequestParam(vo.getRequestParam());
            sysLog.setResponseParam(vo.getResponseParam());
            sysLog.setRequestUri(vo.getRequestUri());
            sysLog.setStartTime(vo.getStartTime());
            sysLog.setEndTime(vo.getFinishTime());
            sysLog.setCostTime(vo.getConsumingTime());
            sysLog.setError(vo.getError());
            sysLog.setCreateUserId(Long.valueOf(vo.getUserId()));

            sysLogManager.save(sysLog);
        });
        return new SysLogEventListener(consumers);
    }

    private void initDesensitizedFieldConfig() {
        // 根据code查字典
        SysDictBo sysDictBo = sysDictManager.getOneByUniqueKey(StringPool.DESENSITIZED_FIELD_VALUE_IN_JSON_DICT_CODE, SysDict::getCode);
        if (sysDictBo == null) {
            return;
        }

        // 查字典明细
        SysDictItemQuery sysDictItemQuery = new SysDictItemQuery();
        sysDictItemQuery.setDictId(sysDictBo.getId());
        List<SysDictItemBo> sysDictItemBos = sysDictItemManager.list(sysDictItemQuery);
        if (CollUtil.isNotEmpty(sysDictItemBos)) {
            for (SysDictItemBo sysDictItemBo : sysDictItemBos) {
                DesensitizedOnJsonComponent.addSensitizedField(sysDictItemBo.getName(), sysDictItemBo.getValue());
            }
        }
    }
}
